package dayTimeRanges

import (
	"fmt"
	"gitee.com/kingzyt/common/idxRangeAllocer"
	"time"
)

// 00:00:00.000000000~23:59:59.999999999, 将一天的时间段划分为没有间隔的N段, 一天的任意一个时间点都能落在一个范围中, 这个范围有一个ID

type DayTimeRanges []*idxRangeAllocer.IdxRange

// [bt,et)
func (self *DayTimeRanges) AddTimeRange(id int64, beginHourPoint int32, endHourPoint int32) error {
	if beginHourPoint < 0 || beginHourPoint > 23 {
		return fmt.Errorf("beginHourPoint(%d) is out of range [0,23]", beginHourPoint)
	}
	if endHourPoint < 0 || endHourPoint > 23 {
		return fmt.Errorf("endHourPoint(%d) is out of range [0,23]", endHourPoint)
	}

	for i := 0; i < len(*self); i++ {
		if (*self)[i].Id == id {
			return fmt.Errorf("id(%d) is already used", id)
		}
	}

	switch {
	case beginHourPoint == endHourPoint:
		return fmt.Errorf("beginHourPoint should be not equal to endHourPoint")

	case beginHourPoint < endHourPoint:
		bt := int64(time.Hour) * int64(beginHourPoint)
		et := int64(time.Hour)*int64(endHourPoint) - 1
		*self = append(*self, &idxRangeAllocer.IdxRange{Id: id, Down: bt, Up: et})

	case beginHourPoint > endHourPoint:
		if endHourPoint != 0 {
			bt0 := int64(time.Hour) * int64(beginHourPoint)
			et0 := int64(time.Hour)*24 - 1
			*self = append(*self, &idxRangeAllocer.IdxRange{Id: id, Down: bt0, Up: et0})

			bt1 := int64(0)
			et1 := int64(time.Hour)*int64(endHourPoint) - 1
			*self = append(*self, &idxRangeAllocer.IdxRange{Id: id, Down: bt1, Up: et1})
		} else {
			bt0 := int64(time.Hour) * int64(beginHourPoint)
			et0 := int64(time.Hour)*24 - 1
			*self = append(*self, &idxRangeAllocer.IdxRange{Id: id, Down: bt0, Up: et0})
		}
	}
	return nil
}

func (self *DayTimeRanges) CheckValid() error {
	_, err := idxRangeAllocer.CheckRangeCross(*self)
	if err != nil {
		return err
	}
	timeSum := int64(0)
	for i := 0; i < len(*self); i++ {
		timeSum += (*self)[i].Up - (*self)[i].Down + 1
	}
	if timeSum != int64(time.Hour)*24 {
		return fmt.Errorf("day time ranges are not filled without gap")
	}
	return nil
}

func (self *DayTimeRanges) GetId(timeStampInDay int64) (id int64, ok bool) {
	for i := 0; i < len(*self); i++ {
		r := (*self)[i]
		if r.Down <= timeStampInDay && timeStampInDay <= r.Up {
			return r.Id, true
		}
	}
	return
}
